package com.gitee.wsl.common.ui.theme


import androidx.compose.ui.text.font.Typeface
import androidx.compose.ui.unit.dp
import com.gitee.wsl.data.store.StoreControl
import com.gitee.wsl.data.store.StoreServer
import com.gitee.wsl.struct.category.CategoryItemWarp
import timber.log.Timber


interface ColorPaletteScope<P: ColorPaletteScheme>{
    var paletteName:String?
    fun factory( themeNameList:List<String>,paletteFactoryCreateHandler:(paletteName: String)->P)
    fun factory(colorPaletteFactory: ColorPaletteFactory<P>)
}

interface ThemeScope<P: ColorPaletteScheme,T: TypographyScheme>{

    fun colorPalette(colorPaletteConfigHandler: ColorPaletteScope<P>.()->Unit)

    fun typography(typographyCreateHandler: T.(P)->Unit)

    fun dimen(dimenDefaultConfig:()->Dimension)
}

interface SubThemeScope<P: ColorPaletteScheme,T: TypographyScheme>:ThemeScope<P,T>{

    fun color(configColorPaletteHandler:P.()->Unit)

}

typealias DefaultTheme = Theme<ColorPaletteScheme, TypographyScheme>


class ThemeConfig<P: ColorPaletteScheme,T: TypographyScheme>{
    var colorScheme:P?=null
    var typography:T?=null
}

interface Dimension{
    val dialogBorderRadius:Float
        get() = 28f.dp.value
}

val Dimension.outlinedButtonStrokeWidth:Float
    get() = 1.dp.value

val defaultDimension = object:Dimension{}


open class Theme<P: ColorPaletteScheme,T: TypographyScheme>(): ThemeScope<P, T> {

    open val colorScheme:P get() = config.colorScheme?:throw IllegalArgumentException("Theme color scheme no set")

    open val typography:T get() = config.typography?:throw IllegalArgumentException("Theme typography scheme no set")

    open val colorSchemeCompose get() = config.colorScheme?.toCompose()?:throw IllegalArgumentException("Theme color scheme no set")

    open val colorSchemeAndroid get() = config.colorScheme?.toAndroid()?:throw IllegalArgumentException("Theme color scheme no set")

    val config = ThemeConfig<P,T>()

    open var dimen:Dimension = defaultDimension


    val typefaceMap= mutableMapOf<String, Typeface>()/*(
        "default" to Typeface.DEFAULT,
        "monospace" to Typeface.MONOSPACE,
    )*/

    protected val colorPaletteFactoryList = mutableListOf<ColorPaletteFactory<P>>()

    constructor(color: P, colorPaletteFactory: ColorPaletteFactory<P>, typography: T) : this() {
        colorPaletteFactory(colorPaletteFactory)
        config.colorScheme = color
        config.typography = typography
    }

    fun getSuportColorThemeList():List<String>{
        val themeList= mutableSetOf<String>()
        colorPaletteFactoryList.forEach {
            themeList.addAll(it.getSuportColorThemeList())
        }
        return themeList.toList()
    }

    override fun colorPalette(colorPaletteConfigHandler: ColorPaletteScope<P>.() -> Unit) {
        var paletteNameSet: String? = null
        colorPaletteConfigHandler(object: ColorPaletteScope<P> {
            override var paletteName: String?
                get() = paletteNameSet
                set(value) {
                    paletteNameSet=value
                }

            override fun factory(themeNameList:List<String>,paletteFactoryCreateHandler: (paletteName: String) -> P) {
                colorPaletteFactory(themeNameList,paletteFactoryCreateHandler)
            }

            override fun factory(colorPaletteFactory: ColorPaletteFactory<P>) {
                colorPaletteFactory(colorPaletteFactory)
            }
        })

        changeTheme(paletteNameSet?: ColorPalette_LIGHT)
    }

    open fun changeTheme(paletteName:String){
        colorPaletteFactoryList.forEach { factory->
            factory.build(paletteName)?.let {
                config.colorScheme=it
                return@forEach
            }
        }
        Timber.d("change theme  to $paletteName is ${config.colorScheme}")
    }

    fun colorPaletteFactory(colorPaletteFactory: ColorPaletteFactory<P>) {
        this.colorPaletteFactoryList.add(colorPaletteFactory)
    }

    fun colorPaletteFactory(
        themeNameList:List<String>,
        paletteFactoryCreateHandler: (paletteName: String) -> P
    ) {
        colorPaletteFactoryList.add(object: ColorPaletteFactory<P> {
            override fun build(name: String): P {
                return paletteFactoryCreateHandler(name)
            }

            override fun getSuportColorThemeList(): List<String> {
                return themeNameList
            }
        })
    }

    override fun typography(typographyCreateHandler:T.(P) -> Unit) {
        typographyCreateHandler(typography,colorScheme)
    }

    fun getTypefaceByName(typefaceName:String, defaultValue: Typeface /*= Typeface.DEFAULT*/, typefaceStyle:Int/*= Typeface.NORMAL*/): Typeface {
        throw Exception("no suptort")
        //return Typeface.create(typefaceName,typefaceStyle)?:defaultValue
    }


    fun mergeTypography(typographyMergeHandler: SubTypographyScheme<T>.()->Unit): SubTheme<P,T> {
        val sub = SubColorPaletteSchemeImp{colorScheme}
        val subTypography = SubTypographyScheme{typography}
        typographyMergeHandler(subTypography)
        return SubTheme(this).apply {
            config.typography=subTypography
            config.colorScheme=sub
        }
    }

    fun mergeColorPalette(colorPaletteMergeHandler: SubColorPaletteSchemeImp<P>.()->Unit): SubTheme<P,T> {
        val sub = SubColorPaletteSchemeImp{colorScheme}
        val subTypography = SubTypographyScheme{typography}
        colorPaletteMergeHandler(sub)
        return SubTheme(this).apply {
            config.typography=subTypography
            config.colorScheme=sub
        }
    }

    fun merge(mergeHandler:(typography: SubTypographyScheme<T>, colorPalette: SubColorPaletteSchemeImp<P>)->Unit): SubTheme<P,T> {
        val subTypography = SubTypographyScheme{typography}
        val subPalette = SubColorPaletteSchemeImp{colorScheme}
        mergeHandler(subTypography,subPalette)
        return  SubTheme(this).apply {
            config.typography=subTypography
            config.colorScheme=subPalette
        }
    }

    /*fun <TYPO:SubTypographyScheme<T>,PALETTE:SubColorPaletteScheme<P>> marge(configHandler: Theme<PALETTE, TYPO>.(T, P)->Unit): Theme<PALETTE, TYPO> {
        val base=this
        val theme= SubThemeExt<P,T,PALETTE,TYPO>(this)
        configHandler(theme,base.typography,base.colorScheme)
        return theme
    }*/

    companion object{


        fun defaultTheme(paletteName: String = ColorPalette_SYSTEM): Theme<ColorPaletteScheme, TypographyScheme> {
            val theme = Theme<ColorPaletteScheme, TypographyScheme>().apply {
                colorPaletteFactory(DefaultColorPaletteFactory())
                config.typography = defaultTypography
                changeTheme(paletteName)
            }
            return theme
        }

        fun <P: ColorPaletteScheme,T: TypographyScheme> defaultTheme(paletteName: String, colorPaletteFactory: ColorPaletteFactory<P>): Theme<P, T> {
            return Theme<P,T>().apply {
                colorPaletteFactory(colorPaletteFactory)
                changeTheme(paletteName)
            }
        }

        fun <P: ColorPaletteScheme,T: TypographyScheme> defaultTheme(paletteName: String, themeNameList:List<String>, paletteFactoryCreateHandler:(paletteName: String)->P): Theme<P, T> {
            return Theme<P,T>().apply {
                colorPaletteFactory(object: ColorPaletteFactory<P> {
                    override fun build(name: String): P {
                        return paletteFactoryCreateHandler(name)
                    }

                    override fun getSuportColorThemeList(): List<String> {
                        return  themeNameList
                    }
                })
                changeTheme(paletteName)
            }
        }


        /*fun theme(config: ThemeScope<ColorPaletteScheme, TypographyScheme>.()->Unit): Theme<ColorPaletteScheme, TypographyScheme> {
            val theme= Theme<ColorPaletteScheme, TypographyScheme>().also {
                it.colorPaletteFactoryList.add(DefaultColorPaletteFactory())
                it.config.typography= defaultTypography
            }
            config(theme)
            return theme
        }*/

        fun <P: ColorPaletteScheme,T: TypographyScheme> theme(config: ThemeScope<P, T>.()->Unit): Theme<P, T> {
            val theme= Theme<P,T>()
            config(theme)
            return theme
        }


        fun <P: ColorPaletteScheme,T: TypographyScheme> theme(baseTheme: Theme<P, T>, config: SubThemeScope<SubColorPaletteScheme, SubTypographyScheme<T>>.()->Unit): SubTheme<P, T> {
            val theme= SubTheme(baseTheme)
            config(theme)
            return theme
        }

        fun <P: ColorPaletteScheme,T: TypographyScheme,PALETTE: SubColorPaletteScheme,TYPO: SubTypographyScheme<T>> theme(baseTheme: Theme<P, T>, colorScheme:PALETTE, typography: TYPO, config: SubThemeScope<PALETTE, TYPO>.()->Unit): SubThemeExt<P,T,PALETTE, TYPO> {
            val theme= SubThemeExt(baseTheme,colorScheme,typography)
            config(theme)
            return theme
        }
    }

    override fun dimen(dimenDefaultConfig: () -> Dimension) {
        dimen = dimenDefaultConfig()
    }

}

open class SubTheme<P: ColorPaletteScheme,T: TypographyScheme>(parentTheme: Theme<P, T>):SubThemeExt<P,T, SubColorPaletteScheme, SubTypographyScheme<T>>(parentTheme,
    SubColorPaletteSchemeImp{ parentTheme.colorScheme }, SubTypographyScheme{ parentTheme.typography }){
}

open class SubThemeOnDefault<PALETTE: SubColorPaletteScheme,TYPO: SubTypographyScheme<TypographyScheme>>(parentTheme: DefaultTheme, colorScheme:PALETTE, typography: TYPO):SubThemeExt<ColorPaletteScheme, TypographyScheme,PALETTE,TYPO>(parentTheme,colorScheme, typography){
}

open class SubThemeExt<P: ColorPaletteScheme,T: TypographyScheme,PALETTE: SubColorPaletteScheme,TYPO: SubTypographyScheme<T>>(val parentTheme: Theme<P, T>, colorScheme:PALETTE, typography: TYPO):
    Theme<PALETTE, TYPO>(),SubThemeScope<PALETTE, TYPO>, StoreControl {

    var STORE_LABEL = ""

    init {
        config.colorScheme = colorScheme
        config.typography = typography
    }

    override fun changeTheme(paletteName:String){
        colorPaletteFactoryList.forEach { factory->
            factory.build(paletteName)?.let {
                config.colorScheme=it
                return@changeTheme
            }
        }
        parentTheme.changeTheme(paletteName)
        STORE_LABEL=paletteName
    }

    override fun color(configColorPaletteHandler: PALETTE.() -> Unit) {
        config.colorScheme?.let { configColorPaletteHandler(it) }
    }

    override fun saveToStore(server: StoreServer) {
        if(colorScheme is StoreControl)
            (colorScheme as StoreControl).saveToStore(server)
        if(typography is StoreControl)
            (typography as StoreControl).saveToStore(server)
    }

    override fun reStore(server: StoreServer) {
        if(colorScheme is StoreControl)
            (colorScheme as StoreControl).reStore(server)
        if(typography is StoreControl)
            (typography as StoreControl).reStore(server)
    }
}


/**
 * 树型 theme 定义
 */
class SubThemeExtCategory<SubCategoryTheme:Any>(baseTheme: SubCategoryTheme, var nodeName:String="",
                                                val categoryLevel:Int=0):
    CategoryItemWarp/*<SubCategoryTheme>*/(baseTheme){
    fun ruleCheck( nodeName:String, level:Int,preNodeName:String?):Boolean{
        return false
    }
}


open class SubCategoryTheme<P: ColorPaletteScheme,T: TypographyScheme,PALETTE: SubColorPaletteScheme,TYPO: SubTypographyScheme<T>,THEME:SubThemeExt<P,T,PALETTE,TYPO>>(parentTheme:THEME ):SubThemeExt<P,T,PALETTE,TYPO>(parentTheme.parentTheme,parentTheme.colorScheme,parentTheme.typography),CategoryThemeScope<PALETTE, TYPO>{

    val rootThemeCategory=SubThemeExtCategory(parentTheme)

    var currentCategory = rootThemeCategory

    val currentTheme :THEME
        get() = currentCategory.data!! as THEME

    var preNodeString:String?=null

    fun initRender(){
        currentCategory = rootThemeCategory
        preNodeString = null
    }


    override fun on(nodeId: String, config: CategoryThemeScope<PALETTE, TYPO>.() -> Unit) {
        val childSubTheme=SubCategoryTheme(this)
        val childNodeThemeCategory=SubThemeExtCategory(childSubTheme,nodeId)
        config(childSubTheme)
        rootThemeCategory.addSubCategoryItem(childNodeThemeCategory as CategoryItemWarp)
    }

    override val colorScheme: PALETTE
        get() = currentTheme.colorScheme

    override val typography: TYPO
        get() = currentTheme.typography

    //var currentNodeLeave:List<String>?=null

    /*private fun changeNode(nodeCategory:SubThemeExtCategory<SubThemeExt<P,T,PALETTE,TYPO>>,nodeIdList:List<String>){
        if(nodeIdList.isNotEmpty()){
            if(nodeCategory.nodeName==nodeIdList[0])
                if(nodeIdList.size==1) {
                    currentCategory = nodeCategory
                }else{
                    nodeCategory.subItemList.find { (it as SubThemeExtCategory).nodeName== nodeIdList[1] }?.let{
                        it as SubThemeExtCategory<SubThemeExt<P,T,PALETTE,TYPO>>
                        changeNode(it ,nodeIdList.subList(1,nodeIdList.size))
                    }
                }
        }
    }

    fun changeNode(vararg nodeId: String){
        currentNodeLeave=nodeId.asList()
        val nodes= mutableListOf(rootThemeCategory.nodeName)
        nodes.addAll(nodeId)
        changeNode(rootThemeCategory,nodes)
    }*/

    fun nodeIn(nodeName: String){
        currentCategory.subItemList.find { (it as SubThemeExtCategory<THEME>).nodeName == nodeName }?.let{
            currentCategory = it as SubThemeExtCategory<THEME>
        }
    }

    fun nodeNext(nodeName: String){
        currentCategory.parent?.let {nodeCagetory->
            nodeCagetory as SubThemeExtCategory<THEME>
            nodeCagetory.subItemList.find { (it as SubThemeExtCategory<THEME>).nodeName == nodeName }?.let{
                currentCategory = nodeCagetory
            }
        }
    }

    fun nodeOut(nodeName: String){
        if(currentCategory.nodeName==nodeName)
            rootThemeCategory.parent?.let {
                currentCategory = it as SubThemeExtCategory<THEME>
            }
    }
}

/**
 * DSL 相关
 */
fun <P: ColorPaletteScheme,T: TypographyScheme,PALETTE: SubColorPaletteScheme,TYPO: SubTypographyScheme<T>> htmlTheme(baseTheme: SubThemeExt<P,T,PALETTE,TYPO>, config:CategoryThemeScope<PALETTE, TYPO>.()->Unit):SubCategoryTheme<P,T,PALETTE, TYPO,SubThemeExt<P,T,PALETTE,TYPO>>{
    val categoryTheme=SubCategoryTheme(baseTheme)
    config(categoryTheme)
    return categoryTheme
}

interface CategoryThemeScope<P: ColorPaletteScheme,T: TypographyScheme>:SubThemeScope<P,T>{
    fun on(nodeId:String,config: CategoryThemeScope<P,T>.()->Unit)
}